import '../map_constants.dart';

///相机位置，这个类包含了所有的可视区域的位置参数。
class CameraPosition {
  ///可视区域指向的方向，以角度为单位，从正北向逆时针方向计算，从0 度到360 度。
  double bearing;

  ///目标位置的屏幕中心点经纬度坐标。
  LatLng target;

  ///目标可视区域的倾斜度，以角度为单位。
  double tilt;

  ///目标可视区域的缩放级别。
  double zoom;

  ///设置地图最大缩放级别 缩放级别范围为[3, 20],超出范围将按最大级别计算 。
  double maxZoom; //TODO iOS

  ///设置最小缩放级别 缩放级别范围为[3, 20],超出范围将按最小级别计算
  double minZoom; //TODO iSO

  CameraPosition({
    this.bearing,
    this.target,
    this.tilt,
    this.zoom = mapDefaultZoom,
    this.minZoom = mapMinZoom,
    this.maxZoom = mapMaxZoom,
  });

  CameraPosition.fromJson(Map<String, dynamic> json) {
    this.bearing = json['bearing'];
    this.target = LatLng.fromJson(json['target']);
    this.tilt = json['tilt'];
    this.zoom = json['zoom'];
    this.minZoom = json['minZoom'];
    this.maxZoom = json['maxZoom'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['bearing'] = bearing;
    data['target'] = target;
    data['tilt'] = tilt;
    data['zoom'] = zoom;
    data['minZoom'] = minZoom;
    data['maxZoom'] = maxZoom;
    return data;
  }

  @override
  String toString() {
    return 'CameraPosition{bearing: $bearing, target: $target, tilt: $tilt, zoom: $zoom, minZoom: $minZoom, maxZoom: $maxZoom}';
  }
}

class ScreenPoint {
  int x, y;

  ScreenPoint({this.x, this.y});

  Map<String, dynamic> toJson() {
    return {
      'x': this.x,
      'y': this.y,
    };
  }

  factory ScreenPoint.fromJson(Map<String, dynamic> map) {
    return new ScreenPoint(
      x: map['x'] as int,
      y: map['y'] as int,
    );
  }

  @override
  String toString() {
    return 'ScreenPoint{x: $x, y: $y}';
  }
}

class LatLng {
  double latitude, longitude;
  String name;

  LatLng(this.latitude, this.longitude, [this.name]);

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['longitude'] = longitude;
    data['latitude'] = latitude;
    data['name'] = name;
    return data;
  }

  LatLng.fromJson(Map<String, dynamic> json) {
    if (json != null) {
      this.latitude = json['latitude'];
      this.longitude = json['longitude'];
      this.name = json['name'];
    }
  }

  bool get valid => latitude != null && longitude != null;

  bool get notZero => valid && latitude > 0.0 && longitude > 0.0;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is LatLng &&
          runtimeType == other.runtimeType &&
          (latitude - other.latitude).abs() < 0.00000000001 &&
          (longitude - other.longitude).abs() < 0.00000000001;

  @override
  int get hashCode => latitude.hashCode ^ longitude.hashCode;

  String delta(LatLng other) {
    if (other == null) return null;
    return "longitude=${this.longitude - other.longitude}, latitude=${this.latitude - other.latitude}";
  }

  @override
  String toString() {
    return 'LatLng{latitude: $latitude, longitude: $longitude, name: $name}';
  }
}

///代表了经纬度划分的一个矩形区域。
class LatLngBounds {
  LatLng northeast, southwest;

  bool get valid =>
      northeast != null &&
      southwest != null &&
      northeast.valid &&
      southwest.valid;

  LatLngBounds.fromJson(Map<String, dynamic> json) {
    this.northeast = LatLng.fromJson(json['northeast']);
    this.southwest = LatLng.fromJson(json['southwest']);
  }

  LatLngBounds(List<LatLng> points) {
    if (points?.isNotEmpty == true && points.length > 1) {
      double minLat = double.infinity, minLng = double.infinity;
      double maxLat = 0, maxLng = 0;
      try {
        for (int i = 0; i < points.length; i++) {
          LatLng p = points[i];
          if (p.valid == false) continue;
          if (p.latitude < minLat) {
            minLat = p.latitude;
          }
          if (p.longitude < minLng) {
            minLng = p.longitude;
          }
          if (p.latitude > maxLat) {
            maxLat = p.latitude;
          }
          if (p.longitude > maxLng) {
            maxLng = p.longitude;
          }
        }
      } catch (e) {
        print(e);
      }
      northeast = LatLng(maxLat, maxLng);
      southwest = LatLng(minLat, minLng);
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['northeast'] = northeast;
    data['southwest'] = southwest;
    return data;
  }

  @override
  String toString() {
    return 'LatLngBounds{northeast: $northeast, southwest: $southwest}';
  }
}

class VisibleRegion {
  LatLng farLeft, farRight, nearLeft, nearRight;
  LatLngBounds latLngBounds;

  VisibleRegion.fromJson(Map<String, dynamic> json) {
    this.farLeft = LatLng.fromJson(json['farLeft']);
    this.farRight = LatLng.fromJson(json['farRight']);
    this.nearLeft = LatLng.fromJson(json['nearLeft']);
    this.nearRight = LatLng.fromJson(json['nearRight']);
    this.latLngBounds = LatLngBounds.fromJson(json['latLngBounds']);
  }

  Map<String, dynamic> toJson() {
    return {
      "farLeft": farLeft,
      "farRight": farRight,
      "nearLeft": nearLeft,
      "nearRight": nearRight,
      "latLngBounds": latLngBounds,
    };
  }

  @override
  String toString() {
    return 'VisibleRegion{farLeft: $farLeft, farRight: $farRight, nearLeft: $nearLeft, nearRight: $nearRight, latLngBounds: $latLngBounds}';
  }
}

enum LogoPosition { bottomLeft, bottomCenter, bottomRight }

enum ZoomPosition { rightCenter, rightBottom }

class MapLocation {
  double latitude; // 30.506518
  double longitude; // 114.379487
  String province; // 湖北省
  String city; // 武汉市
  String district; // 洪山区
  String cityCode; // 027
  String adCode; // 420111
  String address; // 湖北省武汉市洪山区虎泉街靠近中国邮政储蓄银行(吴家湾营业所)
  String country; // 中国
  String road; // 虎泉街
  String poiName; // 中国邮政储蓄银行(吴家湾营业所)
  String street; // 虎泉街
  String streetNum; // =265号
  String aoiName; // =五环天地
  String floor;
  int errorCode = 0;
  String errorInfo;
  int locationType;

  MapLocation({
    this.latitude,
    this.longitude,
    this.province,
    this.city,
    this.district,
    this.cityCode,
    this.adCode,
    this.address,
    this.country,
    this.road,
    this.poiName,
    this.street,
    this.streetNum,
    this.aoiName,
    this.floor,
    this.errorCode,
    this.errorInfo,
    this.locationType,
  });

  Map<String, dynamic> toJson() {
    return {
      'latitude': this.latitude,
      'longitude': this.longitude,
      'province': this.province,
      'city': this.city,
      'district': this.district,
      'cityCode': this.cityCode,
      'adCode': this.adCode,
      'address': this.address,
      'country': this.country,
      'road': this.road,
      'poiName': this.poiName,
      'street': this.street,
      'streetNum': this.streetNum,
      'aoiName': this.aoiName,
      'floor': this.floor,
      'errorCode': this.errorCode,
      'errorInfo': this.errorInfo,
      'locationType': this.locationType,
    };
  }

  factory MapLocation.fromJson(Map<String, dynamic> map) {
    return new MapLocation(
      latitude: map['latitude'] as double,
      longitude: map['longitude'] as double,
      province: map['province'] as String,
      city: map['city'] as String,
      district: map['district'] as String,
      cityCode: map['cityCode'] as String,
      adCode: map['adCode'] as String,
      address: map['address'] as String,
      country: map['country'] as String,
      road: map['road'] as String,
      poiName: map['poiName'] as String,
      street: map['street'] as String,
      streetNum: map['streetNum'] as String,
      aoiName: map['aoiName'] as String,
      floor: map['floor'] as String,
      errorCode: map['errorCode'] as int,
      errorInfo: map['errorInfo'] as String,
      locationType: map['locationType'] as int,
    );
  }

  LatLng get target => LatLng(latitude, longitude);

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is MapLocation &&
          runtimeType == other.runtimeType &&
          target == other.target;

  @override
  int get hashCode => target.hashCode;

  @override
  String toString() {
    return 'MapLocation{latitude: $latitude, longitude: $longitude, address: $address}';
  }
}
